package sf.dsl.example;

import sf.common.exception.SmallOrmException;
import sf.core.DBField;
import sf.core.DBObject;
import sf.database.meta.ColumnMapping;
import sf.database.meta.EntityUtils;
import sf.database.meta.TableMapping;
import sf.spring.util.CollectionUtils;
import sf.tools.ArrayUtils;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Collections;

/**
 * 快速方法
 */
public class QPI {
    public static SimpleField all(SimpleTable c) {
        SimpleField sf = new SimpleField();
        sf.name = "*";
        sf.table = c;
        return sf;
    }

    public static SimpleField all() {
        SimpleField sf = new SimpleField();
        sf.name = "*";
        return sf;
    }

    public static SimpleField column(DBField property) {
        return SimpleField.create(property);
    }

    public static SimpleTable table(DBField property) {
        return SimpleTable.create(property);
    }

    public static SimpleTable table(Class<? extends DBObject> entityClass) {
        return SimpleTable.create(entityClass);
    }

    public static SimpleTable create(TableMapping tableMapping) {
        return SimpleTable.create(tableMapping);
    }

    public static SimpleTable wrappedTable(Example query) {
        return new WrapperSimpleTable(query);
    }

    public static SimpleField wrappedField(Example query) {
        return new WrapperSimpleField(query);
    }

    public static ExpressionSimpleField expressionField(String expression, String... column) {
        return new ExpressionSimpleField(expression, column);
    }

    public static ExpressionSimpleField expressionField(String expression, SimpleField... column) {
        return new ExpressionSimpleField(expression, column);
    }

    public static FunctionSimpleField distinct(String... column) {
        return new FunctionSimpleField().left("DISTINCT ").right("").fileds(column);
    }

    public static FunctionSimpleField distinct(SimpleField... column) {
        return new FunctionSimpleField().left("DISTINCT ").right("").fileds(column);
    }

    public static FunctionSimpleField count() {
        return new FunctionSimpleField("COUNT", "*");
    }

    public static FunctionSimpleField count(String column) {
        return new FunctionSimpleField("COUNT", column);
    }

    public static FunctionSimpleField count(SimpleField column) {
        return new FunctionSimpleField("COUNT", column);
    }

    public static FunctionSimpleField max(String column) {
        return new FunctionSimpleField("MAX", column);
    }

    public static FunctionSimpleField max(SimpleField column) {
        return new FunctionSimpleField("MAX", column);
    }

    public static FunctionSimpleField min(String column) {
        return new FunctionSimpleField("MIN", column);
    }

    public static FunctionSimpleField min(SimpleField column) {
        return new FunctionSimpleField("MIN", column);
    }

    public static FunctionSimpleField avg(String column) {
        return new FunctionSimpleField("AVG", column);
    }

    public static FunctionSimpleField avg(SimpleField column) {
        return new FunctionSimpleField("AVG", column);
    }

    public static FunctionSimpleField sum(String column) {
        return new FunctionSimpleField("SUM", column);
    }

    public static FunctionSimpleField sum(SimpleField column) {
        return new FunctionSimpleField("SUM", column);
    }

    /**
     * 列包装(x1,x2,x3)
     * @param columns
     * @return
     */
    public static FunctionSimpleField wrap(SimpleField... columns) {
        return new FunctionSimpleField("", columns);
    }

    /**
     * @param fnName 函数名称 如:max
     * @param column
     * @return
     */
    public static FunctionSimpleField func(String fnName, String... column) {
        return new FunctionSimpleField(fnName, column);
    }

    /**
     * @param fnName 函数名称 如:max
     * @param column
     * @return
     */
    public static FunctionSimpleField func(String fnName, SimpleField... column) {
        return new FunctionSimpleField(fnName, column);
    }

    /**
     * @param left   如:max(
     * @param right  如:)
     * @param column
     * @return
     */
    public static FunctionSimpleField funcO(String left, String right, String... column) {
        return new FunctionSimpleField().left(left).right(right).fileds(column);
    }

    /**
     * @param left   如:max(
     * @param right  如:)
     * @param column
     * @return
     */
    public static FunctionSimpleField funcO(String left, String right, SimpleField... column) {
        return new FunctionSimpleField().left(left).right(right).fileds(column);
    }

    /**
     * 固定值
     * @param fixVale
     * @return
     */
    public static SimpleField fixColumn(String fixVale) {
        SimpleField sf = new SimpleField();
        sf.setName(fixVale);
        return sf;
    }

    /**
     * 返回原始值
     * @param value
     * @return
     */
    public static RawValue raw(String value) {
        return new RawValue(value);
    }

    public static ICondition and() {
        return new StringCondition(" and ");
    }

    public static ICondition or() {
        return new StringCondition(" or ");
    }

    public static ICondition leftP() {
        return new StringCondition("(");
    }

    public static ICondition rightP() {
        return new StringCondition(")");
    }

    public static ICondition on() {
        return new StringCondition(" on ");
    }

    public static ICondition leftJoin() {
        return QPI.addCondition(" LEFT JOIN ");
    }

    public static ICondition rightJoin() {
        return QPI.addCondition(" RIGHT JOIN ");
    }

    public static ICondition innerJoin() {
        return QPI.addCondition(" INNER JOIN ");
    }

    public static ICondition fullJoin() {
        return QPI.addCondition(" FULL JOIN ");
    }

    public static ICondition crossJoin() {
        return QPI.addCondition(" CROSS JOIN ");
    }

    /**
     * using函数
     * @return
     */
    public static ICondition using(DBField... fields) {
        SimpleField[] columns = new SimpleField[]{};
        if (ArrayUtils.isNotEmpty(fields)) {
            columns = new SimpleField[fields.length];
            for (int i = 0; i < fields.length; i++) {
                SimpleField column = new SimpleField();
                ColumnMapping columnMapping = EntityUtils.getColumn(fields[i]);
                column.setName(columnMapping.getRawColumnName());
                column.setField(columnMapping.getField());
                columns[i] = column;
            }
        }
        FunctionSimpleField functionSimpleField = new FunctionSimpleField(" using", columns);
        return add(functionSimpleField);
    }

    /**
     * 元组 in 如: select * from table where （field1，field2） in ((xxx,yyy),（xxx1，yyy1）)
     * @param fields 按 集合数量/fields个数 分组
     * @return
     */
    public static ICondition in(SimpleField[] fields, Collection<?> values) {
        return row(fields, DBOperator.IN, values, ValueType.listValue);
    }

    /**
     * 元组 in 如: select * from table where （field1，field2） not in ((xxx,yyy),（xxx1，yyy1）)
     * @param fields
     * @param values 按 集合数量/fields个数 分组
     * @return
     */
    public static ICondition notIn(SimpleField[] fields, Collection<?> values) {
        return row(fields, DBOperator.NOT_IN, values, ValueType.listValue);
    }

    /**
     * 行构造函数 (1,2)或 ROW(1,2),两者等效
     * (id,age)=(1,18)
     * @param fields
     * @param operator
     * @param value
     * @param valueType
     * @return
     */
    public static ICondition row(SimpleField[] fields, DBOperator operator, Object value, ValueType valueType) {
        PartCondition condition = new PartCondition();
        condition.setFields(fields);
        condition.setOperator(operator);
        condition.setValueType(valueType);
        condition.setValue(value);
        return condition;
    }

    public static ICondition row(SimpleField[] fields, DBOperator operator, Object value) {
        PartCondition condition = new PartCondition();
        condition.setFields(fields);
        condition.setOperator(operator);
        ValueType valueType = ValueType.noValue;
        if (value != null) {
            valueType = ValueType.singleValue;
            if (value.getClass().isArray()) {
                valueType = ValueType.arrayValue;
            }
        }
        if (value instanceof Collection) {
            valueType = ValueType.listValue;
        }
        condition.setValueType(valueType);
        condition.setValue(value);
        return condition;
    }

    public static ICondition exists(Example query) {
        return new OperatorCondition(" exists ", query);
    }

    public static ICondition notExists(Example query) {
        return new OperatorCondition(" not exists ", query);
    }

    public static ICondition all(Example query) {
        return new OperatorCondition(" all", query);
    }

    public static ICondition any(Example query) {
        return new OperatorCondition(" any", query);
    }

    public static ICondition some(Example query) {
        return new OperatorCondition(" some", query);
    }

    /**
     * 可以使用Example,SimpleTable和普通值
     * @param value
     * @return
     */
    public static ICondition add(Object value) {
        PartCondition c = new PartCondition(value);
        c.setOperator(DBOperator.NOTHING);
        c.setValueType(ValueType.singleValue);
        return c;
    }

    /**
     * 1=1
     * @return
     */
    public static ICondition trueCondition() {
        return new StringCondition("1=1");
    }

    /**
     * 1=0
     * @return
     */
    public static ICondition falseCondition() {
        return new StringCondition("1=0");
    }

    public static ICondition as(String alias) {
        return new StringCondition(" as " + alias);
    }

    /**
     * 返回表信息
     * @param simpleTable
     * @return
     */
    public static ICondition tableInfo(SimpleTable simpleTable) {
        return QPI.add(simpleTable);
    }

    public static ICondition columnInfo(SimpleField... simpleFields) {
        PartCondition c = new PartCondition();
        c.setFields(simpleFields);
        c.setOperator(DBOperator.NOTHING);
        c.setValueType(ValueType.noValue);
        return c;
    }

    public static ICondition addCondition(String condition) {
        if (condition == null) {
            throw new SmallOrmException("Value for condition cannot be null");
        }
        return new StringCondition(condition);
    }

    public static ICondition addCondition(String condition, Object values) {
        return new StringCondition(condition, values);
    }

    public static ICondition addCondition(String condition, Collection<?> values) {
        if (CollectionUtils.isEmpty(values)) {
            return trueCondition();
        }
        return new StringCondition(condition, values);
    }

    public static ICondition addCondition(String condition, Object... values) {
        if (ArrayUtils.isEmpty(values)) {
            return trueCondition();
        }
        return new StringCondition(condition, values);
    }

    public static ICondition addCondition(SimpleField simpleField, DBOperator operator) {
        PartCondition criterion = new PartCondition(simpleField, operator);
        return criterion;
    }

    public static ICondition addCondition(SimpleField simpleField, DBOperator operator, Object value) {
        PartCondition criterion = new PartCondition(simpleField, operator, value);
        return criterion;
    }

    /**
     * @param simpleField
     * @param operator
     * @param value
     * @param defaultValue 填充相等或不相等条件,true是,false为否
     * @return
     */
    public static ICondition addConditionArray(SimpleField simpleField, DBOperator operator, Object value, boolean defaultValue) {
        Collection<?> values = null;
        if (value instanceof Collection) {
            values = (Collection<?>) value;
            if (values.isEmpty()) {
                if (defaultValue) {
                    return trueCondition();
                } else {
                    return falseCondition();
                }
            }
        } else if (value.getClass().isArray()) {
            int length = Array.getLength(value);
            if (length == 0) {
                if (defaultValue) {
                    return trueCondition();
                } else {
                    return falseCondition();
                }
            }
            values = CollectionUtils.arrayToList(value);
        } else {
            values = Collections.singletonList(value);
        }
        PartCondition criterion = new PartCondition(simpleField, operator, values);
        return criterion;
    }

    public static ICondition addConditionBetween(SimpleField simpleField, DBOperator operator, Object value1, Object value2) {
        if (value1 == null || value2 == null) {
            return trueCondition();
        }
        PartCondition criterion = new PartCondition(simpleField, operator, new Object[]{value1, value2});
        return criterion;
    }
}
